import { Injectable, Logger } from '@nestjs/common'
import { InjectEntityManager, InjectRepository } from '@nestjs/typeorm'
import Redis from 'ioredis'

import { isNil } from 'lodash'

import { EntityManager, Like, Repository } from 'typeorm'

import { InjectRedis } from '~/common/decorators/inject-redis.decorator'
import { PagerDto } from '~/common/dto/pager.dto'
import { genIotDeviceKey } from '~/helper/genRedisKey'
import { paginate } from '~/helper/paginate'

import { Pagination } from '~/helper/paginate/pagination'
import { DictItemEntity } from '~/modules/system/dict-item/dict-item.entity'
import { generateUUIDv7 } from '~/utils'
import { DeviceAttrDto, DeviceDto, DeviceQueryDto, DeviceUpdateDto } from './device.dto'
import { DeviceEntity } from './device.entity'
import { DeviceAttrEntity } from './deviceAttr.entity'

@Injectable()
export class DeviceService {
  private logger = new Logger(DeviceService.name)

  constructor(
    @InjectRedis() private readonly redis: Redis,
    @InjectRepository(DeviceEntity)
    private deviceRepository: Repository<DeviceEntity>,
    @InjectRepository(DeviceAttrEntity)
    private deviceAttrRepository: Repository<DeviceAttrEntity>,
    @InjectEntityManager() private entityManager: EntityManager,
  ) { }

  /**
   * 列举所有设备：除去超级管理员
   */
  async findAll({
    page,
    pageSize,
  }: PagerDto): Promise<Pagination<DeviceEntity>> {
    return paginate(this.deviceRepository, { page, pageSize })
  }

  /**
   * 查询设备列表
   */
  async list(queryDto: DeviceQueryDto): Promise<Pagination<DeviceEntity>> {
    const { page, pageSize, sn, mac, name, type, connectState, wearStatus } = queryDto
    const queryBuilder = await this.deviceRepository
      .createQueryBuilder('device')
      .leftJoinAndSelect('device.attr', 'attr')
      .leftJoinAndSelect('device.user', 'user')
      .leftJoinAndMapOne('device.typeDict', DictItemEntity, 'dict', 'dict.value = device.type and dict.type_id = :typId', { typId: 5 })
      .where({
        ...(sn && { sn: Like(`%${sn}%`) }),
        ...(name && { name: Like(`%${name}%`) }),
        ...(!isNil(type) && { type }),
        attr: {
          ...(mac && { mac: Like(`%${mac}%`) }),
          ...(!isNil(connectState) && { connectState }),
          ...(!isNil(wearStatus) && { wearStatus }),
        },
      })
    // this.logger.debug('queryBuilder', queryBuilder.getQueryAndParameters())
    return paginate<DeviceEntity>(queryBuilder, {
      page,
      pageSize,
    })
  }

  async findOne({ uid, sn, mac }: DeviceQueryDto): Promise<DeviceEntity> {
    const info = await this.deviceRepository
      .createQueryBuilder('device')
      .where({
        ...(uid ? { uid } : null),
        ...(sn ? { sn } : null),
        // ...(mac ? { mac } : null),
      })
      .getOne()
    return info
  }

  /**
   * 根据设备获取设备信息
   */
  async info(id: number) {
    const info = await this.deviceRepository
      .createQueryBuilder('device')
      .where({ id })
      .getOne()

    return { ...info }
  }

  async delete(id: number): Promise<void> {
    await this.deviceRepository.delete(id)
  }

  /**
   * 增加设备
   */
  async create({ ...data }: DeviceDto): Promise<{ deviceId: number }> {
    data.uid = generateUUIDv7()
    const attr = await this.deviceAttrRepository.save({ uid: data.uid }, {})
    const device = await this.deviceRepository.save(data, {})
    return { deviceId: device.id }
  }

  /**
   * 更新设备信息
   */
  async update(id, { ...data }: DeviceUpdateDto): Promise<void> {
    await this.deviceRepository.update(id, data)
    await this.redis.del(genIotDeviceKey(data.uid))
  }

  /**
   * 更新设备信息
   */
  async updateByUid(uid, { ...data }: DeviceUpdateDto): Promise<void> {
    await this.deviceRepository.update({ uid }, data)
    await this.redis.del(genIotDeviceKey(uid))
  }

  /**
   * 检查设备是否被用户绑定
   */
  async checkUserByDeviceId(id: number) {
    return false
  }

  /**
   * 保存设备属性
   */
  async saveAttr({ ...data }: DeviceAttrDto): Promise<void> {
    await this.deviceAttrRepository.save(data, {})
  }
}
